﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace LCARSLibrary.Controls
{
    public class Area : LCARSBase
    {
        #region fields

        bool isChecked;
        bool mouseDown;
        bool autoEllipsis;
        bool wordWrap;

        int roundRadius;
        int repeatClickInitDelay;
        int repeatClickRepeatDelay;

        ContentAlignment textAlign;
        Padding textPadding;
        Behaviour behaviour;
        Corner roundCorners;

        Timer timer;

        #endregion

        #region Properties

        [Browsable(true), DefaultValue(false), Category("LCARS")]
        public bool Checked
        {
            get
            {
                return isChecked;
            }
            set
            {
                isChecked = value;
                if (Behaviour == LCARSLibrary.Behaviour.Checkable)
                {
                    mouseDown = isChecked;
                    OnCheckedChanged(this, EventArgs.Empty);
                }
            }
        }

        [Browsable(true), DefaultValue(1000), Category("LCARS")]
        public int RepeatClickInitDelay
        {
            get { return repeatClickInitDelay; }
            set { repeatClickInitDelay = value; if (repeatClickInitDelay < 100) repeatClickInitDelay = 100; }
        }

        [Browsable(true), DefaultValue(100), Category("LCARS")]
        public int RepeatClickRepeatDelay
        {
            get { return repeatClickRepeatDelay; }
            set { repeatClickRepeatDelay = value; if (repeatClickRepeatDelay < 100) repeatClickRepeatDelay = 100; }
        }

        [Editor("System.ComponentModel.Design.MultilineStringEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        public override string Text { get { return base.Text; } set { base.Text = value; } }

        [Browsable(true), DefaultValue(false), Category("LCARS")]
        public bool WordWrap
        {
            get { return wordWrap; }
            set { wordWrap = value; base.Invalidate(); }
        }

        [Browsable(true), DefaultValue(typeof(SoundEffect), "None"), Category("LCARS")]
        public SoundEffect SoundEffect { get; set; }

        [Browsable(true), DefaultValue(typeof(Font), "LCARSGTJ3, 15.75pt")]
        public override Font Font
        {
            get
            {
                return base.Font;
            }
            set
            {
                base.Font = value;
            }
        }

        [Browsable(true), DefaultValue(false), Category("LCARS")]
        public bool AutoEllipsis
        {
            get { return autoEllipsis; }
            set { autoEllipsis = value; base.Invalidate(); }
        }

        [Browsable(true), DefaultValue(typeof(ContentAlignment), "BottomLeft"), Category("LCARS")]
        public ContentAlignment TextAlign
        {
            get { return textAlign; }
            set { textAlign = value; base.Invalidate(); }
        }

        [Browsable(true), DefaultValue(typeof(Padding), "0,0,0,0"), Category("LCARS")]
        public Padding TextPadding
        {
            get { return textPadding; }
            set { textPadding = value; base.Invalidate(); }
        }

        [Browsable(true), DefaultValue(typeof(Corner), "None"), Category("LCARS")]
        public Corner RoundCorners
        {
            get { return roundCorners; }
            set { roundCorners = value; base.Invalidate(); }
        }

        [Browsable(true), DefaultValue(0), Category("LCARS")]
        public int RoundRadius
        {
            get { return roundRadius; }
            set { roundRadius = value; base.Invalidate(); }
        }

        [Browsable(true), DefaultValue(typeof(Behaviour), "None"), Category("LCARS")]
        public Behaviour Behaviour
        {
            get
            {
                return behaviour;
            }
            set
            {
                behaviour = value;
                isChecked = mouseDown = false;

                base.Invalidate();
            }
        }
     
        [Browsable(true), DefaultValue(false), Category("LCARS")]
        public bool Editable { get; set; }

        #endregion

        #region events

        [Browsable(true), Category("LCARS")]
        public event EventHandler RepeatClick;

        [Browsable(true), Category("LCARS")]
        public event EventHandler CheckedChanged;


        protected virtual void OnRepeatClick(object sender, EventArgs e)
        {
            EventHandler temp = RepeatClick;
            if (temp != null)
            {
                temp(sender, e);
            }
        }

        protected virtual void OnCheckedChanged(object sender, EventArgs e)
        {
            base.Invalidate();

            EventHandler temp = CheckedChanged;
            if (temp != null)
            {
                temp(sender, e);
            }
        }

        #endregion


        public Area(string Text)
        {
            base.DoubleBuffered = true;
            base.SetStyle(ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
            base.SetStyle(ControlStyles.StandardDoubleClick, false);
            base.BackColor = Color.Transparent;
            base.Text = Text;
            base.Font = new Font("LCARSGTJ3", 15.75f);
            this.Margin = new Padding(2);
            this.Size = new System.Drawing.Size(130, 70);

            behaviour = Behaviour.None;
            roundCorners = Corner.None;

            isChecked = false;
            mouseDown = false;
            autoEllipsis = false;

            roundRadius = 0;
            repeatClickInitDelay = 1000;
            repeatClickRepeatDelay = 100;

            timer = new Timer();
            timer.Tick += new EventHandler(timer_Tick);
            timer.Interval = repeatClickInitDelay;

            textAlign = ContentAlignment.BottomLeft;
            textPadding = new Padding(0);
        }

        public Area()
            : this("")
        {

        }


        public void PlaySoundEffect()
        {
            LCARSBase.PlaySoundEffect(SoundEffect);
        }

        public void PerformClick()
        {
            throw new NotImplementedException();
        }

        private void DrawText(Graphics g)
        {
            TextFormatFlags flags = TextFormatFlags.Default;

            if (WordWrap)
                flags |= TextFormatFlags.WordBreak;

            if (autoEllipsis)
                flags |= TextFormatFlags.EndEllipsis;

            switch (textAlign)
            {
                case ContentAlignment.BottomCenter:
                    flags |= TextFormatFlags.Bottom | TextFormatFlags.HorizontalCenter;
                    break;
                case ContentAlignment.BottomLeft:
                    flags |= TextFormatFlags.Bottom | TextFormatFlags.Left;
                    break;
                case ContentAlignment.BottomRight:
                    flags |= TextFormatFlags.Bottom | TextFormatFlags.Right;
                    break;
                case ContentAlignment.MiddleCenter:
                    flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter;
                    break;
                case ContentAlignment.MiddleLeft:
                    flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.Left;
                    break;
                case ContentAlignment.MiddleRight:
                    flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.Right;
                    break;
                case ContentAlignment.TopCenter:
                    flags |= TextFormatFlags.Top | TextFormatFlags.HorizontalCenter;
                    break;
                case ContentAlignment.TopLeft:
                    flags |= TextFormatFlags.Top | TextFormatFlags.Left;
                    break;
                case ContentAlignment.TopRight:
                    flags |= TextFormatFlags.Top | TextFormatFlags.Right;
                    break;
                default:
                    break;
            }

            Rectangle textRect = this.ClientRectangle;
            textRect.X += this.TextPadding.Left;
            textRect.Y += this.TextPadding.Top;
            textRect.Width -= (this.TextPadding.Left + this.TextPadding.Right);
            textRect.Height -= (this.TextPadding.Top + this.TextPadding.Bottom);

            TextRenderer.DrawText(g, this.Text, this.Font, textRect, this.TextColor, flags);
        }

        private void DrawBackground(Graphics g, bool down)
        {
            using (SolidBrush brush = new SolidBrush(down ? this.SecondaryColor : this.Color))
            using (GraphicsPath path = new GraphicsPath())
            {
                RoundedRectangle.CreateRoundRectPath(path, ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Height, roundRadius, roundCorners, this.Padding);
                g.FillPath(brush, path);
            }
        }


        private void timer_Tick(object sender, EventArgs e)
        {
            timer.Interval = repeatClickRepeatDelay;

            if (mouseDown)
                this.OnRepeatClick(this, EventArgs.Empty);
        }


        protected override void OnPaddingChanged(EventArgs e)
        {
            base.Invalidate();
            base.OnPaddingChanged(e);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.Invalidate();
            base.OnSizeChanged(e);
        }

        protected override void OnTextChanged(EventArgs e)
        {
            base.Invalidate();
            base.OnTextChanged(e);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            DrawText(g);
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            base.OnPaintBackground(e);

            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            DrawBackground(g, mouseDown);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            this.Focus();

            if (e.Button == MouseButtons.Left && Behaviour != Behaviour.None && !Editable)
            {
                mouseDown = true;

                if (Behaviour == LCARSLibrary.Behaviour.Checkable)
                {
                    isChecked = !isChecked;
                }
                else if (Behaviour == Behaviour.RepeatClick)
                {
                    timer.Interval = repeatClickInitDelay;
                    timer.Start();
                }

                base.Invalidate();
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);

            if (e.Button == MouseButtons.Left && Behaviour != Behaviour.None && !Editable)
            {
                if (Behaviour == Behaviour.Checkable)
                    OnCheckedChanged(this, EventArgs.Empty);

                if (!isChecked || Behaviour != Behaviour.Checkable)
                    mouseDown = false;

                if (Behaviour == Behaviour.RepeatClick)
                {
                    timer.Stop();
                }

                base.Invalidate();
            }
        }

        protected override void OnClick(EventArgs e)
        {
            if (mouseDown && Behaviour != Behaviour.None && !Editable)
            {
                PlaySoundEffect();
                base.OnClick(e);
            }
        }

        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            base.OnKeyPress(e);

            if (Editable)
            {
                if (e.KeyChar == (char)Keys.Escape)
                {
                    this.Text = String.Empty;
                }
                else if (e.KeyChar == (char)Keys.Back)
                {
                    if (!String.IsNullOrEmpty(this.Text))
                        this.Text = this.Text.Remove(this.Text.Length - 1, 1);
                }
                else if (e.KeyChar == (char)Keys.Return)
                {
                    this.Text += "\n";
                }
                else
                {
                    this.Text += e.KeyChar;
                }
            }
        }
    }
}
